# coding:utf-8
import json
import re

from app.libs.rules import rules
from app.libs.tools import SplitSentences, merge_sub_sentence
from app.models.document_dom import DocumentDom


class ParseDocument:

    def __init__(self, paragraphs):
        self.paragraphs = paragraphs
        self.abstract_sign = 0
        self.sign = len(paragraphs)
        self.category_position = len(paragraphs)
        self.ckwx_sign = ['[M]', '[N]', '[J]', '[P]', '[Z]', '[G]', '[O]', '[S]', '[D]', '[R]', '[K]', '[W]', '[B]',
                          '[A]', '[Q]', '[L]', '[V]', '[C]', '[T]', '[I]', '[Y]', '[H]', '[E]']
        self.has_category = 0
        self.char_index = 0
        self.ckwx_position = len(paragraphs)
        self.contents = []
        self.paragraph_content = []
        self.current_paragraph_index = 0
        self.insertList = []
        self.current_check_content = ''
        self.current_check_index = ''

    def appendInsertList(self, paragraph, check):
        self.insertList.append({
            'content': paragraph.text,
            'check_content': self.current_check_content,
            'node': paragraph.path,
            'check': check
        })
        for item in self.insertList:
            item['check_content'] = self.current_check_content

    def insert(self):
        for item in self.insertList:
            final = item.copy()
            if len(final['check_content']) < 10:
                final['check'] = 0
            self.contents.append(final)
        self.insertList = []
        self.current_check_content = ''
        return 'continue'

    @staticmethod
    def count_english_words(paragraph):
        words = re.findall(r'\b[a-zA-Z]+\b', paragraph)
        return len(words)

    @staticmethod
    def countLanguage(paragraphs):
        count = 0
        zh = ''
        english_words = 0
        for s in paragraphs:
            if '\u4e00' <= s <= '\u9fa5':
                count += 1
                zh += s
        if count == 0:
            english_words = ParseDocument.count_english_words(paragraphs)
        return count, zh, english_words

    @staticmethod
    def is_pure_english(sentence):
        return all(char.isalpha() or char.isspace() for char in sentence)

    @staticmethod
    def matchCategoryIndex(content):
        pattern1 = '((\(|（){1}(一|二|三|四|五|六|七|八|九|\d{1,2})(\)|）){1})|((一|二|三|四|五|六|七|八|九|\d{1,2})(.|。|,| ){1})'
        pattern2 = '(([(（]){1}(一|二|三|四|五|六|七|八|九|\d{1,2})([)）]){1})|((一|二|三|四|五|六|七|八|九|\d{1,2})(.|。|,| ){1})'
        print(re.match(pattern1, content))
        print(re.match(pattern2, content))
        return re.match(pattern1, content) or re.match(pattern2, content)

    @staticmethod
    def isAbstract(content):
        if len(content) > 20:
            return False
        if content[0:2] == '摘要':
            return True
        if content[0:4] == '中文摘要':
            return True
        if content[0:4] == '【摘要】':
            return True
        if content[0:4] == '[摘要]':
            return True
        return False

    @staticmethod
    def check_doc_str(text):
        list = ['[M]', '[N]', '[J]', '[P]', '[Z]', '[G]', '[O]', '[S]', '[D]', '[R]', '[K]', '[W]', '[B]',
                '[A]', '[Q]', '[L]', '[V]', '[C]', '[T]', '[I]', '[Y]', '[H]', '[E]']
        for i in list:
            if str(i) in text:
                return True
        return False

    def getAbstractIndex(self):
        for index, paragraph in enumerate(self.paragraphs):
            print(paragraph.text)
            zh_count, zh_content, english_words = ParseDocument.countLanguage(paragraph.text)
            if ParseDocument.isAbstract(zh_content):
                self.abstract_sign = index

    def parseIsCategoryHeader(self, index, paragraph):
        zh_count, zh_content, english_words = ParseDocument.countLanguage(paragraph.text)
        paragraph_length = len(paragraph.text.strip())
        if zh_content == '目录' and paragraph_length < 140:
            if self.has_category == 0:
                self.category_position = self.char_index
            self.has_category = 1
            self.current_check_content = paragraph.text
            self.current_check_index = index
            self.appendInsertList(paragraph, 0)
            return self.insert()

    def parseIsCategory(self, index, paragraph):
        zh_count, zh_content, english_words = ParseDocument.countLanguage(paragraph.text)
        if self.char_index - self.category_position <= 80 and ParseDocument.matchCategoryIndex(paragraph.text) and len(
                zh_content) < 35 and len(paragraph.text) < 140:
            self.category_position = self.char_index
            self.current_check_content = paragraph.text
            self.current_check_index = index
            self.appendInsertList(paragraph, 0)
            return self.insert()
        # if ParseDocument.matchCategoryIndex(paragraph) and len(zh_content) < 18 and len(paragraph.text) < 40:
        #     self.category_position = self.char_index
        #     self.current_check_content = paragraph
        #     self.current_check_index = index
        #     self.appendInsertList(paragraph, 0)
        #     return self.insert()

    def uncheckAbstract(self, index, paragraph):
        if index == self.abstract_sign and index !=0:
            self.current_check_content = paragraph.text
            self.current_check_index = index
            self.appendInsertList(paragraph, 0)
            return self.insert()

    def uncheckBeforeAbstract(self, index, paragraph):
        zh_count, zh_content, english_words = self.countLanguage(paragraph.text)
        if index < self.abstract_sign and zh_count < 140:
            self.current_check_content = paragraph.text
            self.current_check_index = index
            self.appendInsertList(paragraph, 0)
            return self.insert()

    def isCkwxHeader(self, index, paragraph):
        zh_count, zh_content, english_words = self.countLanguage(paragraph.text)
        if zh_content == '参考文献' and len(paragraph.text) < 140:
            self.ckwx_position = index
            self.current_check_content = paragraph.text
            self.current_check_index = index
            self.appendInsertList(paragraph, 0)
            return self.insert()

    def uncheckBeforeCkwx(self, index, paragraph):
        zh_count, zh_content, english_words = self.countLanguage(paragraph.text)
        if index > self.ckwx_position:
            if ParseDocument.check_doc_str(paragraph.text) or re.search('([\[|【|［]\d{1,3}[】|\]|］])',
                                                                        paragraph.text.strip()[0:4]):
                if zh_count < 140:
                    self.current_check_content = paragraph.text
                    self.current_check_index = index
                    self.appendInsertList(paragraph, 0)
                    return self.insert()

    def parentPath(self, paragraph):
        currentNode = f'-{paragraph.node}_{paragraph.index}'
        parentPath = paragraph.path.split(currentNode)[0]
        return parentPath

    def style2dict(self, spanStyle):
        styles = spanStyle.split(';')
        dict = {}
        for style in styles:
            if style:
                try:
                    if ':' in style:
                        dict[style.split(':')[0]] = style.split(':')[1]
                except Exception as e:
                    pass
        return dict

    def FontSize(self, fontsize):
        return float(fontsize.replace('pt', '').replace('em', ''))

    def CheckPNodeAttrs(self, paragraph):
        zh_count, zh_content, english_words = self.countLanguage(paragraph.text)
        Pnode = DocumentDom.query.filter_by(order_number=paragraph.order_number) \
            .filter_by(path=self.parentPath(paragraph)).first()
        pattrs = json.loads(Pnode.attrs)
        if 'class' in pattrs.keys():
            paragraphClass = pattrs['class'][0]
            if ('TOC' in paragraphClass or '目录' in paragraphClass) and zh_count < 30:
                return False
            if ('Heading' in paragraphClass or '标题' in paragraphClass) and zh_count < 20:
                return False
            if 'Header' in paragraphClass and zh_count < 20:
                return False
            if 'Caption' in paragraphClass and zh_count < 40:
                return False
            if 'List-Paragraph' in paragraphClass and zh_count < 20:
                return False
        if 'style' in pattrs.keys():
            paragraphStyle = pattrs['style']
            if 'text-align:center' in paragraphStyle and zh_count < 30:
                return False
        spanAttrs = json.loads(paragraph.attrs)
        if 'style' in spanAttrs.keys():
            spanStyle = spanAttrs['style']
            styleDict = self.style2dict(spanStyle)
            if 'font-family' in styleDict.keys() and 'font-size' in styleDict.keys():
                if '黑体' == styleDict['font-family'] and self.FontSize(styleDict['font-size']) >= 14 and zh_count < 25:
                    return False
        return True

    def checkByRules(self, index, paragraph):

        paragraph.txt = paragraph.text.strip()
        zh_count, zh_content, english_words = self.countLanguage(paragraph.text)
        for rule in rules:
            if rule['type'] == 'in':
                if rule['keywords'] in zh_content:
                    if rule['min_type'] == 'zh':
                        if zh_count < rule['min_length']:
                            self.current_check_content = paragraph.text
                            self.current_check_index = index
                            self.appendInsertList(paragraph, 0)
                            return self.insert()
                    if rule['min_type'] == 'all':
                        if len(paragraph.text) < rule['min_length']:
                            self.current_check_content = paragraph.text
                            self.current_check_index = index
                            self.appendInsertList(paragraph, 0)
                            return self.insert()
            if rule['type'] == 'equal':
                if rule['keywords'] == zh_content:
                    if rule['min_type'] == 'zh':
                        if zh_count < rule['min_length']:
                            self.current_check_content = paragraph.text
                            self.current_check_index = index
                            self.appendInsertList(paragraph, 0)
                            return self.insert()
                    if rule['min_type'] == 'all':
                        if len(paragraph.text) < rule['min_length']:
                            self.current_check_content = paragraph.text
                            self.current_check_index = index
                            self.appendInsertList(paragraph, 0)
                            return self.insert()
        if paragraph.node == 'span':
            check_attrs = self.CheckPNodeAttrs(paragraph)
            if not check_attrs:
                self.current_check_content += paragraph.text
                self.current_check_index = index
                self.appendInsertList(paragraph, 0)
                return self.insert()
            if zh_count > 0 or english_words == 0:
                if len(paragraph.text) <= 18:
                    if len(self.current_check_content + paragraph.text) > 20:
                        if index - self.current_check_index == 1:
                            self.current_check_content += paragraph.text
                            self.current_check_index = index
                            self.appendInsertList(paragraph, 1)
                            self.insert()
                        else:
                            if self.insertList != []:
                                self.insert()
                            self.current_check_content += paragraph.text
                            self.current_check_index = index
                            self.appendInsertList(paragraph, 1)
                            self.insert()
                    else:
                        self.current_check_content += paragraph.text
                        self.current_check_index = index
                        self.appendInsertList(paragraph, 1)
                elif len(paragraph.text.strip()) > 18 and len(paragraph.text.strip()) <= 55 and len(paragraph.text) > 0:
                    self.current_check_content += paragraph.text
                    self.current_check_index = index
                    self.appendInsertList(paragraph, 1)
                    return self.insert()
                else:
                    if self.insertList != []:
                        self.insert()
                    paragraph.text = paragraph.text.strip()
                    sentence_list = SplitSentences('([。！])', paragraph.text)
                    for sentence_list_item in sentence_list:
                        if len(sentence_list_item) > 55:
                            sub_sentences_list = SplitSentences('([,，])', sentence_list_item)
                            paragraph_sentence_list = merge_sub_sentence(sub_sentences_list)
                            for paragraph_sentence_list_item in paragraph_sentence_list:
                                self.contents.append(
                                    {
                                        'content': paragraph_sentence_list_item,
                                        'check_content': paragraph_sentence_list_item,
                                        'node': paragraph.path,
                                        'check': 1
                                    }
                                )
                        else:
                            if len(sentence_list_item) > 0:
                                self.contents.append(
                                    {
                                        'content': sentence_list_item,
                                        'check_content': sentence_list_item,
                                        'node': paragraph.path,
                                        'check': 1
                                    }
                                )
                    return 'continue'
            else:
                if english_words < 5:
                    self.current_check_content = paragraph.text
                    self.current_check_index = index
                    self.appendInsertList(paragraph, 0)
                    return self.insert()
                if english_words >= 5 and english_words <= 15:
                    self.current_check_content = paragraph.text
                    self.current_check_index = index
                    self.appendInsertList(paragraph, 0)
                    return self.insert()
                if english_words > 15:
                    paragraph.text = paragraph.text.strip()
                    sentence_list = SplitSentences('([.,])', paragraph.text)
                    for english_sentence in sentence_list:
                        item_zh_count, item_zh_content, item_english_words = self.countLanguage(english_sentence)
                        if item_english_words > 4:
                            self.contents.append(
                                {
                                    'content': english_sentence,
                                    'check_content': english_sentence,
                                    'node': paragraph.path,
                                    'check': 1
                                }
                            )
                        else:
                            self.contents.append(
                                {
                                    'content': english_sentence,
                                    'check_content': english_sentence,
                                    'node': paragraph.path,
                                    'check': 0
                                }
                            )
        if paragraph.node == 'tr':
            self.current_check_content += paragraph.text
            self.current_check_index = index
            self.appendInsertList(paragraph, 1)
            return self.insert()

    def cut(self):
        self.getAbstractIndex()
        paragraph_content = []
        for index, paragraph in enumerate(self.paragraphs):
            
            paragraph_length = len(paragraph.text.strip())
            if paragraph_length > 0:
                paragraph.text = paragraph.text.replace('【', '[').replace('】', ']').replace('［', '').replace('］', '')
                self.char_index += paragraph_length
                self.paragraph_content.append(paragraph.text)
                if self.uncheckAbstract(index, paragraph) == 'continue':
                    continue
                if self.parseIsCategoryHeader(index, paragraph) == 'continue':
                    continue
                if self.parseIsCategory(index, paragraph) == 'continue':
                    continue
                if self.uncheckBeforeAbstract(index, paragraph) == 'continue':
                    continue
                if self.isCkwxHeader(index, paragraph) == 'continue':
                    continue
                if self.uncheckBeforeCkwx(index, paragraph) == 'continue':
                    continue
                if self.checkByRules(index, paragraph) == 'continue':
                    continue


if __name__ == '__main__':

    bot = ParseDocument('')
    bot.cut()
    for index, item in enumerate(bot.contents):
        print(item)
        # if item['content'] != item['check_content']:
        #     print(bot.contents[index-1])
        #     print(item)
